package com.beta.cust.bind.datasync.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.beta.cat.service.RedissonService;
import com.beta.cust.bind.datasync.constant.BusinessConstant;
import com.beta.cust.bind.datasync.constant.CacheConstans;
import com.beta.cust.bind.datasync.dto.ExternalCustInfoDTO;
import com.beta.cust.bind.datasync.dto.ExternalcontactByUserIdDTO;
import com.beta.cust.bind.datasync.dto.SelectReq;
import com.beta.cust.bind.datasync.mapper.entity.CustInfo;
import com.beta.cust.bind.datasync.mapper.entity.EmpCustRef;
import com.beta.cust.bind.datasync.mapper.entity.EmployeeInfo;
import com.beta.cust.bind.datasync.service.ICustInfoService;
import com.beta.cust.bind.datasync.service.IEmpCustRefService;
import com.beta.cust.bind.datasync.service.IEmployeeInfoService;
import com.beta.cust.bind.datasync.service.ISyncWechatWorkCustInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author：wangjiang
 */
@Service
@Slf4j
public class SyncWechatWorkCustInfoImpl implements ISyncWechatWorkCustInfo {

    @Autowired
    private RedissonService redissonService;

    @Autowired
    private IEmployeeInfoService employeeInfoService;

    @Autowired
    private WechatWorkServiceImpl wechatWorkService;

    @Autowired
    private AuthCorpInfoServiceImpl corpInfoService;

    @Autowired
    private ICustInfoService custInfoService;

    @Autowired
    private IEmpCustRefService empCustRefService;

    @Override
    public boolean syncCustInfo(String corpId) {
        String lockKey = String.format(CacheConstans.SYNC_CUST_INFO, corpId);
        try {
            if (redissonService.tryLock(lockKey, CacheConstans.WAIT_TIME)) {//一直锁到同步结束
                LocalDateTime excuteBatchTime = LocalDateTime.now();
                SelectReq req = new SelectReq();
                req.setPageSize(10);
                while (true) {
                    //1、分页查询用户信息
                    IPage<EmployeeInfo> employPage = employeeInfoService.selectPage(req);
                    List<EmployeeInfo> employeeInfoList = employPage.getRecords();
                    if (CollectionUtils.isEmpty(employeeInfoList)) {
                        break;
                    }
                    req.setId(employeeInfoList.get(employeeInfoList.size() - 1).getId());
                    //批量接口返回参数中未提供userId->externalUserId映射关系 这里只能单条查询
                    for (EmployeeInfo employeeInfo : employeeInfoList) {
                        String agentId = null;
                        if (!employeeInfo.getCorpId().equals(corpId)) {//不是上游企业，则查询下游企业的agentId
                            agentId = corpInfoService.getAgentIdByCorpId(employeeInfo.getCorpId());
                            if (agentId == null) {
                                log.warn("没有查询到下游企业[{}]的agentId", employeeInfo.getCorpId());
                                continue;
                            }
                        }
                        //分页游标，再下次请求时填写以获取之后分页的记录，如果已经没有更多的数据则返回空
                        while (true) {
                            String cursor = "";
                            //2、查询用户对应的客户信息
                            ExternalcontactByUserIdDTO dto = wechatWorkService.queryCustInfos(false, employeeInfo.getUserId(), employeeInfo.getCorpId(), agentId, cursor);
                            if(ObjectUtils.isEmpty(dto)){
                                break;
                            }
                            List<ExternalcontactByUserIdDTO.ExternalContactListDTO> synCustInfoList = dto.getExternalContactList();
                            if (CollectionUtils.isEmpty(synCustInfoList)) {
                                break;
                            }
                            syncCustList(synCustInfoList, employeeInfo.getCorpId());
                            syncEmpCustList(synCustInfoList, employeeInfo.getUserId(), employeeInfo.getCorpId());
                            cursor = dto.getNextCursor();
                            if (StringUtils.isBlank(cursor)) {
                                break;
                            }
                        }

                    }
                }
                afterDeleteCust(excuteBatchTime);
            } else {
                log.info("当前已有定时任务运行中...");
                return false;
            }
        } catch (Exception e) {
            log.error("syncWechatWorkEmployeeInfo error：{}", e.getMessage(), e);
            return false;
        } finally {
            redissonService.unlock(lockKey);
        }
        return true;
    }

    @Override
    public void createCustInfo(String userID, String externalUserID, String corpId, String agentId) {
        // 根据 ExternalUserID 查询客户信息
        ExternalCustInfoDTO custInfoDto = wechatWorkService.getExternalCustInfo(externalUserID, corpId, agentId);
        if (custInfoDto.getErrcode().intValue() == 0) {
            ExternalCustInfoDTO.ExternalContactDTO dto = custInfoDto.getExternalContact();
            CustInfo custInfoOld = custInfoService.getOne(new LambdaQueryWrapper<CustInfo>()
                    .eq(CustInfo::getCorpId, corpId)
                    .eq(CustInfo::getExternalUserid, externalUserID));
            // 封装客户对象
            CustInfo newCustInfo = getCallBackCust(dto, custInfoOld, corpId);
            if (Objects.isNull(custInfoOld)) {
                // 保存 外部客户
                custInfoService.save(newCustInfo);
            } else {
                // 客户已存在 更新
                custInfoService.updateById(custInfoOld);
            }

            // 封装关联关系表，要先去数据库查询该员工有没有客户，如果员工有客户就不用添加了  如果员工没有客户就需要添加
            EmpCustRef empCustRef = empCustRefService.getOne(new LambdaQueryWrapper<EmpCustRef>()
                    .eq(EmpCustRef::getCorpId, corpId)
                    .eq(EmpCustRef::getUserId, userID)
                    .eq(EmpCustRef::getExternalUserid, externalUserID));
            if (Objects.isNull(empCustRef)) {
                empCustRef = new EmpCustRef();
                empCustRef.setCorpId(corpId);
                empCustRef.setUserId(userID);
                empCustRef.setExternalUserid(externalUserID);
                empCustRef.setDelFlag(BusinessConstant.IS_NOT_DEL_FLAG);
                empCustRef.setCreateTime(Timestamp.valueOf(LocalDateTime.now()));
                empCustRef.setUpdateTime(Timestamp.valueOf(LocalDateTime.now()));
                // 保存关联关系
                empCustRefService.save(empCustRef);
            } else {
                empCustRef.setDelFlag(BusinessConstant.IS_NOT_DEL_FLAG);
                empCustRef.setUpdateTime(Timestamp.valueOf(LocalDateTime.now()));
                empCustRefService.updateById(empCustRef);
            }
        }
    }

    @Override
    public void deleteCust(String corpId, String externalUserID, String userID) {
        log.info("客户回调-删除客户:{}", externalUserID);
        //1.删除员工-客户信息
        EmpCustRef empCustRef = new EmpCustRef();
        empCustRef.setDelFlag(BusinessConstant.IS_DEL_FLAG);
        empCustRefService.update(empCustRef, new LambdaQueryWrapper<EmpCustRef>()
                .eq(EmpCustRef::getCorpId, corpId)
                .eq(EmpCustRef::getUserId, userID)
                .eq(EmpCustRef::getExternalUserid, externalUserID));
    }


    private void syncCustList(List<ExternalcontactByUserIdDTO.ExternalContactListDTO> detailDTOS, String corpId) {
        //1.获取所有的ExternalUserid集合
        Set<String> externalUseridList = new HashSet<>();
        for (ExternalcontactByUserIdDTO.ExternalContactListDTO dto : detailDTOS) {
            externalUseridList.add(dto.getExternalContact().getExternalUserid());
        }
        //2.根据corpId,ExternalUserid查询数据库
        List<CustInfo> existList = custInfoService.list(new LambdaQueryWrapper<CustInfo>().eq(CustInfo::getCorpId, corpId)
                .in(CustInfo::getExternalUserid, externalUseridList));
        List<CustInfo> addList = new ArrayList<>();
        List<CustInfo> updateList = new ArrayList<>();
        //3.1数据库全部数据都不存在 则直接新增
        if (CollectionUtils.isEmpty(existList)) {
            addList = getCustList(detailDTOS, corpId);
        } else {
            List<String> existExternalUserIdList = existList.stream().map(CustInfo::getExternalUserid).collect(Collectors.toList());
            Map<String, CustInfo> empMap = existList.stream().collect(Collectors.toMap(CustInfo::getExternalUserid, a -> a));
            //3.2数据库存在则新增 数据库不存在则修改
            for (ExternalcontactByUserIdDTO.ExternalContactListDTO dto : detailDTOS) {
                if (existExternalUserIdList.contains(dto.getExternalContact().getExternalUserid())) {
                    updateList.add(getCust(dto, empMap.get(dto.getExternalContact().getExternalUserid()), corpId));
                } else {
                    CustInfo custInfo = new CustInfo();
                    addList.add(getCust(dto, custInfo, corpId));
                }
            }
        }
        if (!CollectionUtils.isEmpty(addList)) {
            custInfoService.saveBatch(addList);
        }
        if (!CollectionUtils.isEmpty(updateList)) {
            custInfoService.updateBatchById(updateList);
        }
    }


    private void syncEmpCustList(List<ExternalcontactByUserIdDTO.ExternalContactListDTO> detailDTOS, String userId, String corpId) {
        //1.获取所有的externalUserid集合
        Set<String> externalUseridList = new HashSet<>();
        for (ExternalcontactByUserIdDTO.ExternalContactListDTO dto : detailDTOS) {
            externalUseridList.add(dto.getExternalContact().getExternalUserid());
        }
        //2.根据corpId,externalUserid查询数据库
        List<EmpCustRef> existList = empCustRefService.list(new LambdaQueryWrapper<EmpCustRef>()
                .eq(EmpCustRef::getCorpId, corpId)
                .eq(EmpCustRef::getUserId, userId)
                .in(EmpCustRef::getExternalUserid, externalUseridList));
        List<EmpCustRef> addList = new ArrayList<>();
        List<EmpCustRef> updateList = new ArrayList<>();
        //3.1数据库全部数据都不存在 则直接新增
        if (CollectionUtils.isEmpty(existList)) {
            addList = getEmpCustList(detailDTOS, userId, corpId);
        } else {
            List<String> existExternalUserIdList = existList.stream().map(EmpCustRef::getExternalUserid).collect(Collectors.toList());
            Map<String, EmpCustRef> empCustMap = existList.stream().collect(Collectors.toMap(EmpCustRef::getExternalUserid, a -> a));
            //3.2数据库存在则新增 数据库不存在则新增
            for (ExternalcontactByUserIdDTO.ExternalContactListDTO dto : detailDTOS) {
                if (existExternalUserIdList.contains(dto.getExternalContact().getExternalUserid())) {
                    updateList.add(getEmpCust(dto, empCustMap.get(dto.getExternalContact().getExternalUserid()), userId, corpId));
                } else {
                    EmpCustRef empCustRef = new EmpCustRef();
                    addList.add(getEmpCust(dto, empCustRef, userId, corpId));
                }
            }
        }
        if (!CollectionUtils.isEmpty(addList)) {
            empCustRefService.saveBatch(addList);
        }
        if (!CollectionUtils.isEmpty(updateList)) {
            empCustRefService.updateBatchById(updateList);
        }
    }

    private List<CustInfo> getCustList(List<ExternalcontactByUserIdDTO.ExternalContactListDTO> detailDTOS, String corpId) {
        List<CustInfo> custInfos = new ArrayList<>();
        for (ExternalcontactByUserIdDTO.ExternalContactListDTO dto : detailDTOS) {
            CustInfo custInfo = new CustInfo();
            custInfo = getCust(dto, custInfo, corpId);
            custInfos.add(custInfo);
        }
        return custInfos;
    }

    private CustInfo getCust(ExternalcontactByUserIdDTO.ExternalContactListDTO dto, CustInfo custInfo, String corpId) {
        custInfo.setCorpId(corpId);
        custInfo.setExternalUserid(dto.getExternalContact().getExternalUserid());
        custInfo.setName(dto.getExternalContact().getName());
        if (StringUtils.isNotBlank(dto.getExternalContact().getAvatar())) {
            custInfo.setAvatar(dto.getExternalContact().getAvatar());
        }
        custInfo.setType(dto.getExternalContact().getType());
        if (dto.getExternalContact().getType() == 2) {
            // 仅当联系人类型是企业微信用户时有此字段
            custInfo.setCorpName(dto.getExternalContact().getCorpName());
            custInfo.setCorpFullName(dto.getExternalContact().getCorpFullName());
            custInfo.setPosition(dto.getExternalContact().getPosition());
        }
        if (0 != dto.getExternalContact().getGender()) {
            custInfo.setGender(dto.getExternalContact().getGender());
        }
        custInfo.setUnionid(dto.getExternalContact().getUnionid());
        custInfo.setDelFlag(BusinessConstant.IS_NOT_DEL_FLAG);
        custInfo.setUpdateTime(Timestamp.valueOf(LocalDateTime.now()));
        return custInfo;
    }

    private CustInfo getCallBackCust(ExternalCustInfoDTO.ExternalContactDTO dto, CustInfo custInfo, String corpId) {
        if (null == custInfo) {
            custInfo = new CustInfo();
        }
        custInfo.setCorpId(corpId);
        custInfo.setExternalUserid(dto.getExternalUserid());
        custInfo.setName(dto.getName());
        if (StringUtils.isNotBlank(dto.getAvatar())) {
            custInfo.setAvatar(dto.getAvatar());
        }
        custInfo.setType(dto.getType());
        if (dto.getType() == 2) {
            // 仅当联系人类型是企业微信用户时有此字段
            custInfo.setCorpName(dto.getCorpName());
            custInfo.setCorpFullName(dto.getCorpFullName());
            custInfo.setPosition(dto.getPosition());
        }
        if (0 != dto.getGender()) {
            custInfo.setGender(dto.getGender());
        }
        custInfo.setUnionid(dto.getUnionid());
        custInfo.setDelFlag(BusinessConstant.IS_NOT_DEL_FLAG);
        custInfo.setUpdateTime(Timestamp.valueOf(LocalDateTime.now()));
        return custInfo;
    }

    private List<EmpCustRef> getEmpCustList(List<ExternalcontactByUserIdDTO.ExternalContactListDTO> detailDTOS, String userId, String corpId) {
        List<EmpCustRef> custInfos = new ArrayList<>();
        for (ExternalcontactByUserIdDTO.ExternalContactListDTO dto : detailDTOS) {
            EmpCustRef empCustRef = new EmpCustRef();
            empCustRef = getEmpCust(dto, empCustRef, userId, corpId);
            custInfos.add(empCustRef);
        }
        return custInfos;
    }

    private EmpCustRef getEmpCust(ExternalcontactByUserIdDTO.ExternalContactListDTO dto, EmpCustRef empCustRef, String userId, String corpId) {
        empCustRef.setCorpId(corpId);
        empCustRef.setUserId(userId);
        empCustRef.setExternalUserid(dto.getExternalContact().getExternalUserid());
        empCustRef.setDelFlag(BusinessConstant.IS_NOT_DEL_FLAG);
        empCustRef.setUpdateTime(Timestamp.valueOf(LocalDateTime.now()));
        return empCustRef;
    }

    /**
     * 后置删除操作
     *
     * @param excuteBatchTime
     */
    private void afterDeleteCust(LocalDateTime excuteBatchTime) {
        try {
            //避免数据太少 快速结束 误删除
            Thread.sleep(2000);
            CustInfo custInfo = new CustInfo();
            custInfo.setDelFlag(BusinessConstant.IS_DEL_FLAG);
            custInfoService.update(custInfo, new LambdaQueryWrapper<CustInfo>().eq(CustInfo::getDelFlag, BusinessConstant.IS_NOT_DEL_FLAG)
                    .lt(CustInfo::getUpdateTime, Timestamp.valueOf(excuteBatchTime)));

            EmpCustRef empCustRef = new EmpCustRef();
            empCustRef.setDelFlag(BusinessConstant.IS_DEL_FLAG);
            empCustRefService.update(empCustRef, new LambdaQueryWrapper<EmpCustRef>().eq(EmpCustRef::getDelFlag, BusinessConstant.IS_NOT_DEL_FLAG)
                    .lt(EmpCustRef::getUpdateTime, Timestamp.valueOf(excuteBatchTime)));
        } catch (Exception e) {
            log.error("afterDeleteCust error:", e);
        }
    }
}

